/*
 * json_utilits.hpp
 *
 *  Created on: 2021年10月15日
 *      Author: guyadong
 */

#ifndef COMMON_SOURCE_CPP_JSON_UTILITS_HPP_
#define COMMON_SOURCE_CPP_JSON_UTILITS_HPP_
#include <regex>
#include <mutex>
#include "base64.hpp"
#include "nlohmann/json.hpp"
#ifndef _BASIC_JSON_TPL_PARAMS_

#define _BASIC_JSON_TPL_PARAMS_                                 \
    ObjectType, ArrayType, StringType, BooleanType,             \
    NumberIntegerType, NumberUnsignedType, NumberFloatType,     \
    AllocatorType, JSONSerializer, BinaryType

#endif // !_BASIC_JSON_TPL_PARAMS_

#ifndef _BASIC_JSON_TPL_PARAM_DECL_

#define _BASIC_JSON_TPL_PARAM_DECL_                                                     \
	template<typename U, typename V, typename... Args> class ObjectType = std::map,        \
	template<typename U, typename... Args> class ArrayType = std::vector,                  \
	class StringType = std::string, class BooleanType = bool,                              \
	class NumberIntegerType = std::int64_t,                                                \
	class NumberUnsignedType = std::uint64_t,                                              \
	class NumberFloatType = double,                                                        \
	template<typename U> class AllocatorType = std::allocator,                             \
	template<typename T, typename SFINAE = void> class JSONSerializer = adl_serializer,    \
	class BinaryType = std::vector<std::uint8_t>

#endif // !_BASIC_JSON_TPL_PARAM_DECL_


#ifndef _BASIC_JSON_TPL_DECLARATION_
#define _BASIC_JSON_TPL_DECLARATION_ template<_BASIC_JSON_TPL_PARAM_DECL_>
#endif // !_BASIC_JSON_TPL_DECLARATION_

#ifndef  _BASIC_JSON_TPL_
#define _BASIC_JSON_TPL_                                           \
    nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType,   \
    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \
    AllocatorType, JSONSerializer, BinaryType>

#endif // ! _BASIC_JSON_TPL_

namespace json_utilits{
	template<typename T, _BASIC_JSON_TPL_PARAM_DECL_>
	T get_value(const _BASIC_JSON_TPL_ & params, const std::string& name, const T & defaultValue)
	{
		if (params.contains(name))
		{
			return params[name].get<T>();
		}
		return defaultValue;
	}
	_BASIC_JSON_TPL_DECLARATION_
	_BASIC_JSON_TPL_ get_value(const _BASIC_JSON_TPL_ & params, const std::string& name, const _BASIC_JSON_TPL_ & defaultValue)
	{
		if (params.contains(name))
		{
			return params[name];
		}
		return defaultValue;
	}
	template<typename T,_BASIC_JSON_TPL_PARAM_DECL_>
	void fill_field( T& output, const _BASIC_JSON_TPL_ & j, const std::string &field)
	{
		if (j.contains(field))output = j[field].get<T>();
	}
	_BASIC_JSON_TPL_DECLARATION_
	void fill_field(_BASIC_JSON_TPL_& output, const _BASIC_JSON_TPL_ & j, const std::string &field)
	{
		if (j.contains(field))output = j[field];
	}
	/**
	 * 返回枚举类型变量的名字字符串
	 * 枚举类型 E 必须支持 nlohmann::json 的名字序列化和返序列
	 */
	template<typename E>
	const std::string& name_of(E e)
	{
		static std::map<E, std::string> names;
		static std::mutex name_mutex;
		if (!names.count(e))
		{
			// double check
			std::lock_guard<std::mutex> guard(name_mutex);
			if (!names.count(e))
			{
				dtalk::json j;
				to_json(j, e);
				names[e] = std::regex_replace(j.dump(), std::regex("^\"(.*)\"$"), "$1");
			}
		}
		return names[e];
	}
	//************************************
	// 将类型为string的BASE64编译的字符串转为解码的string json 对象
	// @param    const dtalk::json & strJson
	//************************************
	_BASIC_JSON_TPL_DECLARATION_
	void from_base64(_BASIC_JSON_TPL_ & j)
	{
		if (j.is_string())
		{
			/** 保存BASE64字符串解码后的二进制数据 */
			j = gdface::base64_decode(j.get<std::string>());

		}
	}
	//************************************
	// 将类型为string的json对象中的二进制数据转为BASE64编码的 json 对象
	// @param    const dtalk::json & strJson
	//************************************
	_BASIC_JSON_TPL_DECLARATION_
	_BASIC_JSON_TPL_ to_base64(const _BASIC_JSON_TPL_&j)
	{
		_BASIC_JSON_TPL_ out;
		if (j.is_string())
		{
			auto v = j.get<std::string>();
			out = gdface::base64_encode(v);
		}
		return out;
	}
} /** namespace json_utilits */



#endif /* COMMON_SOURCE_CPP_JSON_UTILITS_HPP_ */
